package com.fzk.router;

import io.netty.handler.codec.http.HttpMethod;

import java.util.ArrayList;
import java.util.List;

/**
 * 匹配规则
 *
 * @author fzk
 * @datetime 2023-04-15 00:59:57
 */
public class MatchRule {
    final String bindPath;
    final ArrayList<HttpMethod> methods;

    private MatchRule(String bindPath, List<HttpMethod> methods) {
        this.bindPath = bindPath;
        this.methods = new ArrayList<>(methods);// 必须拷贝，不然可能被外部修改
    }

    public boolean match(String path, HttpMethod method) {
        if (this.bindPath.equals(path)) {
            for (HttpMethod m : methods) {
                if (m.equals(method)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static MatchRule of(String path, List<HttpMethod> methods) {
        if (path.contains("*")) {
            return new AnyMatchRule(path, methods);
        }
        return new MatchRule(path, methods);
    }

    public static class AnyMatchRule extends MatchRule {
        final String[] subBinds;

        // path = /fs/*, /*, /*/fs, /fs/*hello/world*
        private AnyMatchRule(String bindPath, List<HttpMethod> methods) {
            super(bindPath, methods);
            this.subBinds = splitPath(bindPath);
        }

        public boolean match(String path, HttpMethod method) {
            for (HttpMethod m : this.methods) {
                if (m.equals(method)) {
                    return pathMatch(path);
                }
            }
            return false;
        }

        private boolean pathMatch(String path) {
            String[] subPaths = splitPath(path);
            for (int i = 0; i < subPaths.length && i < subBinds.length; i++) {
                String subReg = subBinds[i];
                String subP = subPaths[i];
                if (subReg.endsWith("*") && subP.startsWith(subReg.substring(0, subReg.length() - 1))) {
                    if (i == subBinds.length - 1) {// 比如 /fs/hello*
                        return true;
                    }
                    continue;
                } else if ((subReg.startsWith("/*") && subP.endsWith(subReg.substring(2))) || subReg.equals(subP)) {
                    continue;
                }
                return false;
            }
            return subBinds.length == subPaths.length;
        }

        // 将路径/fs/*hello//world*//切分为 ["/fs","/*hello","/world*","/"]
        private static String[] splitPath(String path) {
            ArrayList<String> result = new ArrayList<>();
            int i, j;
            for (i = 0; i < path.length(); i = j) {
                for (j = i + 1; j < path.length(); j++) {
                    if (path.charAt(j) == '/') {
                        break;
                    }
                }
                String curPart = path.substring(i, j);
                if (!result.isEmpty() && "/".equals(result.get(result.size() - 1))) {
                    result.set(result.size() - 1, curPart);
                } else {
                    result.add(curPart);
                }
            }
            return result.toArray(new String[0]);
        }
    }
}
